#ifndef __UDP_SERVER_HPP__
#define __UDP_SERVER_HPP__
#include<iostream>
#include<string>
#include<memory>
#include<functional>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"log.hpp"
#include"InetAddr.hpp"
#define DIE(code) do{exit(code);}while(0)
using func_t = std::function<std::string(const std::string&)>;

const static uint16_t DEFAULT_PORT = 8080;
const static std::string DEFAULT_IP = "127.0.0.1";//表示本机地址
class Udp_server
{
public:
    Udp_server(func_t func,uint16_t port = DEFAULT_PORT)
        :_addr(port)    
        ,_func(func)
    {}
    void Init()
    {
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if(_sockfd < 0){
            LOG(log_level::FATAL) << "create socket failed"<<strerror(errno);
            DIE(1);
        }
        LOG(log_level::INFO) << "create socket success fd: "<<_sockfd;
        int n = ::bind(_sockfd, (struct sockaddr*)_addr.GetAddr(), _addr.GetAddrLen());
        if(n < 0){
            LOG(log_level::FATAL) << "bind socket failed"<<strerror(errno);
            DIE(2);
        }
        LOG(log_level::INFO) << "bind socket success";
    }
    void Start()
    {
        _is_running = true; 
        while(true){
            char _recv_buf[1024];
            struct sockaddr_in peer;//定义一个结构体变量来保存对端的地址信息
            socklen_t len = sizeof(peer);//必须设定
            ssize_t n = recvfrom(_sockfd, _recv_buf, sizeof(_recv_buf)-1, 0, (struct sockaddr*)&peer, &len);//采用阻塞式等待 recvfrom函数返回时，表示收到了一个数据报，返回值是收到的数据的长度，如果返回值是-1，表示出错
            if(n > 0){
                _recv_buf[n] = '\0';
                std::string result = _func(_recv_buf);
                ::sendto(_sockfd, result.c_str(), result.size(), 0, (struct sockaddr*)&peer, sizeof(peer));//发送数据报
                
            }
            
        }
        _is_running = false;
    }
    ~Udp_server()
    {   
        if(_sockfd >= 0)
            ::close(_sockfd);
    }
private:
    int _sockfd = -1;
    InetAddr _addr;
    bool _is_running = false;
    func_t _func;//回调函数处理业务
};


#endif